package org.advanced.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author John.zhang
 * @version Id: NioSelectorClient, v 1.0 2020/12/17 14:03 ZhiYong Exp $
 * 基于多路复用器来实现客户端的连接处理
 */
public class NioSelectorClient {

    static Selector selector;

    public static void main(String[] args) {
        try {
            selector = Selector.open();
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("localhost", 8080));

            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            while (true) {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    iterator.remove();
                    if (next.isConnectable()) {
                        handleConnect(next);
                    } else if (next.isReadable()) {
                        handleRead(next);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    private static void handleConnect(SelectionKey selectionKey) throws IOException {
        //当前客户端的连接已经就绪
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        //稳妥一点，其实肯定已经就绪了
        if (channel.isConnectionPending()) {
            channel.finishConnect();
        }
        channel.configureBlocking(false);
        channel.write(ByteBuffer.wrap("Hello server,I'm NIO client".getBytes()));
        //监听读的事件，经过上面的轮询建立通道进而走到下面的代码
        channel.register(selector, SelectionKey.OP_READ);
    }


    private static void handleRead(SelectionKey selectionKey) throws IOException {
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        channel.read(byteBuffer);
        System.out.println("client receive Msg:" + new String(byteBuffer.array()));
    }

}
